package concurrecy;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class Meal {
    private int no;
    public Meal(int no) {
        this.no = no;
    }

    @Override
    public String toString() {
        return "Meal " + no;
    }
}

class Waiter implements Runnable {
    private Restaurant restaurant;

    public Waiter(Restaurant restaurant) {
        this.restaurant = restaurant;
    }

    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                synchronized (this) {
                    while (restaurant.getMeal() == null) { // 菜还没准备好，等厨师做菜
                        System.out.println("waiter waiting ... ");
                        wait();
                    }

                    Meal meal = restaurant.getMeal();
                    System.out.println("take " + meal);
                    synchronized (restaurant.getChef()) {
                        restaurant.setMeal(null); // 把菜端走了
                        restaurant.getChef().notifyAll(); // 催厨师做菜
                    }
                }
            }
        } catch(InterruptedException e) {
            System.out.println("waiter interrupted");
        }
        System.out.println("waiter go home");
    }
}

class Chef implements Runnable {
    private Restaurant restaurant;
    private int count = 0;

    public Chef(Restaurant restaurant) {
        this.restaurant = restaurant;
    }

    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                synchronized (this) {
                    while (restaurant.getMeal() != null) { // 食物还没有被端走，等服务员端走
                        System.out.println("chef waiting ... ");
                        wait();
                    }
                }
                Meal meal = new Meal(count++);
                System.out.println("make " + meal);
                synchronized (restaurant.getWaiter()) {
                    restaurant.setMeal(meal); // 生产好了食物
                    restaurant.getWaiter().notifyAll(); // 叫服务员上菜
                }

                if (count > 10)
                    restaurant.closeDoor(); // 食物卖完了，关门
                TimeUnit.MILLISECONDS.sleep(500); // 休息一下
            }
        } catch(InterruptedException e) {
            System.out.println("chef interrupted");
        }
        System.out.println("chef go home");
    }
}

class Restaurant {
    private Chef chef = new Chef(this);
    private Waiter waiter = new Waiter(this);
    private volatile Meal meal;

    private ExecutorService executorService = Executors.newCachedThreadPool();

    public Restaurant() {
        executorService.execute(chef);
        executorService.execute(waiter);
    }

    /**
     * 关门，打烊
     */
    public void closeDoor() {
        System.out.println("closeDoor");
        executorService.shutdownNow();
    }

    public Chef getChef() {
        return chef;
    }

    public Waiter getWaiter() {
        return waiter;
    }

    public Meal getMeal() {
        return meal;
    }

    public void setMeal(Meal meal) {
        this.meal = meal;
    }
}


/**
 * 餐厅 （生产者-消费者）
 */
public class RestaurantDemo {
    public static void main(String[] args) {
        new Restaurant();
    }
}
